﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Contract.Business.Entity;
using Contract.Business.Filter;
using Generic.Business.Process;
using Contract.Business.Manager;
using Contract.Business.Validation;
using System.Transactions;

namespace Contract.Business.Process
{
    //Criado por : Gustavo
    //Data       : 10/25/2011 12:19:32 AM
    public class BPVenda : BPGeneric<BEVenda, BMVenda, BVVenda, FEVenda>
    {
        #region Singleton
        private BMSubGrupoTamanho bmSubGrupoTamanho;
        private BMSubGrupoTamanho businessManagerSubGrupoTamanho
        {
            get
            {
                if (bmSubGrupoTamanho == null)
                    bmSubGrupoTamanho = new BMSubGrupoTamanho();

                return bmSubGrupoTamanho;
            }
        }

        private BMVendaItem bmVendaItem;
        private BMVendaItem businessManagerVendaItem
        {
            get
            {
                if (bmVendaItem == null)
                    bmVendaItem = new BMVendaItem();

                return bmVendaItem;
            }
        }

        private BMPagamento bmPagamento;
        private BMPagamento businessManagerPagamento
        {
            get
            {
                if (bmPagamento == null)
                    bmPagamento = new BMPagamento();

                return bmPagamento;
            }
        }

        private BPCliente bpCliente;
        private BPCliente businessProcessCliente
        {
            get
            {
                if (bpCliente == null)
                    bpCliente = new BPCliente();

                return bpCliente;
            }
        }
        #endregion

        public void Cancelar(int codigo, string motivo)
        {
            this.BusinessManager.Cancelar(codigo, motivo);
        }

        public override BEVenda Salvar(BEVenda entidade)
        {
            //Adiciona o endereço do cliente caso seja um novo
            BEEnderecoCliente novoEndereco = businessProcessCliente.adicionarEndereco(entidade.Cliente);
            if (novoEndereco != null)
                entidade.EnderecoEntrega = novoEndereco;

            bool novaVenda = (entidade.Codigo == 0);

            entidade = base.Salvar(entidade);

            //Caso esteja alterando, deverá apagar os itens e pagamentos excluídos
            BPVendaItem vendaItemProcess = new BPVendaItem();
            BPPagamento pagamentoProcess = new BPPagamento();

            if (!novaVenda)
            {
                List<BEVendaItem> itens = ObterItensVenda(entidade.Codigo);
                foreach (BEVendaItem i in itens)
                {
                    if (!entidade.Itens.Any(q => q.Codigo == i.Codigo))
                        businessManagerVendaItem.Excluir(i);
                }

                List<BEPagamento> pagamentos = ObterPagamentosVenda(entidade.Codigo);
                foreach (BEPagamento p in pagamentos)
                {
                    if (!entidade.Pagamentos.Any(q => q.Codigo == p.Codigo))
                        businessManagerPagamento.Excluir(p);
                }
            }

            entidade.Itens.ForEach(q => q.CodigoVenda = entidade.Codigo);
            vendaItemProcess.SalvarLista(entidade.Itens);

            entidade.Pagamentos.ForEach(q => q.CodigoVenda = entidade.Codigo);
            pagamentoProcess.SalvarLista(entidade.Pagamentos);

            if (novaVenda)
            {
                BMCliente managarCliente = new BMCliente();
                managarCliente.IncrementarPizzaContador(entidade.CodigoCliente);

                //Cria a saida/chegada
                BESaidaChegada saidaChegada = new BESaidaChegada();
                saidaChegada.CodigoVenda = entidade.Codigo;

                BMSaidaChegada bmSaidaChegada = new BMSaidaChegada();
                bmSaidaChegada.Salvar(saidaChegada);
            }

            return entidade;
        }

        public List<BEVendaItem> ObterItensVenda(int codigoVenda)
        {
            return this.BusinessManager.ObterItensVenda(codigoVenda);
        }

        public List<BEPagamento> ObterPagamentosVenda(int codigoVenda)
        {
            return this.BusinessManager.ObterPagamentosVenda(codigoVenda);
        }

        public void TransmitirVendasWeb()
        {
            //Lista 100 vendas
            List<BEVenda> vendas = BusinessManager.ObterNaoEnviadas();

            while (vendas != null && vendas.Count > 0)
            {
                //Envia as vendas para a web

                //Altera o "Enviado" para true
                BusinessManager.SalvarEnviadas(vendas);

                //Lista mais 100 itens
                vendas = BusinessManager.ObterNaoEnviadas();
            }
        }

        public void aplicarPromocoes(BEProduto produto, int quantidade, ref decimal valor, out decimal valorTotal,
                                     BESubGrupoTamanho subGrupoTamanho, List<BEVendaItem> listaItens, DayOfWeek day,
                                     bool borda, BEConfiguracao config)
        {
            try
            {
                valorTotal = 0;

                int qtdPizzaGrande = 0;
                if (listaItens != null && listaItens.Count > 0)
                    qtdPizzaGrande = listaItens.Where(q => q.CodigoTamanho == config.CodigoTamanhoPizzaGrande
                                                           && !q.Cupom).Sum(q => q.Quantidade);

                if (day == DayOfWeek.Monday)
                {
                    //Segunda - Na compra de uma pizza grande mais R$ 10,00 ganhe uma pizza pequena Classic ou mais R$ 12,00 ganhe uma pizza pequena Prime
                    //Se for pequena
                    if (subGrupoTamanho.CodigoTamanho == config.CodigoTamanhoPizzaPequena)
                    {
                        //verifica se já foi usada a promoção. Caso ainda não foi usada, o preço será de 6,00 ou 8,00
                        int qtdVezesUsadas = listaItens.Where(q => q.CodigoTamanho == config.CodigoTamanhoPizzaPequena &&
                                                                   (q.ValorUnitario == 10)).Count();

                        if (qtdPizzaGrande > qtdVezesUsadas)
                        {
                            //Deixei esta lógica apenas para não precisar refazê-la
                            if (subGrupoTamanho.CodigoSubGrupo == config.CodigoSubGrupoClassic)
                                valor = 10;
                            else
                                valor = 10;
                        }
                    }
                }
                else if (day == DayOfWeek.Tuesday)
                {
                    //Terça e Quarta - Na compra de uma pizza grande a segunda pizza grande sai pela metade do preço!
                    if (subGrupoTamanho.SubGrupo.CodigoGrupo == config.CodigoGrupoPizza &&
                        subGrupoTamanho.CodigoTamanho == config.CodigoTamanhoPizzaGrande &&
                        (qtdPizzaGrande % 2 == 1))
                    {
                        valor = valor / 2;
                    }
                }
                else if (day == DayOfWeek.Wednesday)
                {
                    //Não tem mais promoção na quarta-feira
                }
                else if (day == DayOfWeek.Thursday)
                {
                    //Quinta - Na compra de qualquer pizza, a borda recheada é por nossa conta
                    //Promoção aplicada no final da função
                }
                else if (day == DayOfWeek.Friday)
                {
                    //Sexta - Na compra de uma pizza grande a segunda pizza grande sai pelo preço da pizza média!
                    if (subGrupoTamanho.SubGrupo.CodigoGrupo == config.CodigoGrupoPizza &&
                        subGrupoTamanho.CodigoTamanho == config.CodigoTamanhoPizzaGrande &&
                        (qtdPizzaGrande % 2 == 1))
                    {
                        BESubGrupoTamanho subGrupoTamanhoMedia = businessManagerSubGrupoTamanho.ObterTodos(new FESubGrupoTamanho()
                        {
                            CodigoSubGrupo = subGrupoTamanho.CodigoSubGrupo,
                            CodigoTamanho = config.CodigoTamanhoPizzaMedia
                        }).FirstOrDefault();

                        if (subGrupoTamanhoMedia != null)
                            valor = subGrupoTamanhoMedia.Preco;
                    }
                }
                else
                {
                    if (day == DayOfWeek.Saturday || day == DayOfWeek.Sunday)
                    {

                        //Sábado e Domingo - Na compra de duas pizzas grandes, mais R$ 10,00 ganhe uma pizza pequena classic, ou mais R$ 12,00 ganhe uma pizza pequena prime
                        if (subGrupoTamanho.CodigoTamanho == config.CodigoTamanhoPizzaPequena)
                        {
                            if (qtdPizzaGrande > 0 && qtdPizzaGrande % 2 == 0)
                            {
                                int qtdPequena;
                                if (listaItens != null && listaItens.Count > 0)
                                {
                                    qtdPequena = listaItens.Where(q => q.CodigoTamanho == config.CodigoTamanhoPizzaPequena).Sum(q => q.Quantidade);

                                    if (qtdPequena * 2 < qtdPizzaGrande)
                                    {
                                        //Deixei esta lógica apenas para não precisar refazê-la
                                        if (subGrupoTamanho.CodigoSubGrupo == config.CodigoSubGrupoClassic)
                                            valor = 10;
                                        else
                                            valor = 10;
                                    }
                                }
                            }
                        }
                    }
                }

                //Aplicando a promoção de quinta-feira
                if (borda && day != DayOfWeek.Thursday)
                    valor += config.ValorBorda;

                //Na compra de uma pizza grande, o refri vai de graça
                valorTotal = valor * quantidade;

                if (subGrupoTamanho != null)
                {
                    if (produto.SubGrupo.CodigoGrupo == config.CodigoGrupoBebida)
                    {
                        int qtdBebidas = listaItens.Where(q => q.Produto.SubGrupo.CodigoGrupo == config.CodigoGrupoBebida).Sum(q => q.Quantidade);

                        //Na terça, quarta e sexta, existe a promoção na pizza grande
                        if (day == DayOfWeek.Wednesday || day == DayOfWeek.Tuesday || day == DayOfWeek.Friday)
                            qtdPizzaGrande = qtdPizzaGrande - listaItens.Where(q => q.CodigoTamanho == config.CodigoTamanhoPizzaGrande
                                                                                    && (q.Cupom || q.ValorUnitario < 31)).Sum(q => q.Quantidade); // Tira as pizzas na promoção

                        for (int i = 0; i < quantidade; i++)
                        {
                            if (qtdPizzaGrande > (qtdBebidas + i))
                            {
                                decimal valorBebida = subGrupoTamanho.Preco;
                                if (subGrupoTamanho.CodigoSubGrupo == config.CodigoSubGrupoSuco)
                                    valorTotal -= (valorBebida - 1);
                                else
                                    valorTotal -= valorBebida;
                            }
                            else
                                break;
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
